package ru.maxmatveev.dyndao;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

/**
 * Sorting operation object.
 * Use as parameter in DAO methods to specify more than one order-by parameter.
 * @author Max Matveev
 *         Date: Dec 20, 2008
 *         Time: 5:34:38 PM
 */
public class Ordering {
    /** Sorting direction. */
    public static enum Direction {
        /** ASC ordering */
        ASC,
        /** DESC ordering */
        DESC
    }
    /** Field field  */
    private String field;
    /** Field direction  */
    private Direction direction;
    /** Field child  */
    private Ordering child;

    /**
     * Constructor taking order-by field name and direction.
     * @param field Field name
     * @param direction Sorting direction
     */
    public Ordering(String field, Direction direction) {
        this.field = field;
        this.direction = direction;
    }

    /**
     * Constructor taking order-by field name. Uses default Ascending sorting direction.
     * @param field Field name
     */
    public Ordering(String field) {
        this.field = field;
        this.direction = Direction.ASC;
    }

    /**
     * Add another order-by value. Uses default Ascending sorting.
     * @param field Field name
     * @return next object in sorting chain. Add next sorting parameter (if any) to it
     */
    public Ordering Order(String field) {
        Ordering order = new Ordering(field);
        this.child = order;
        return order;
    }

    /**
     * Add another order-by value.
     * @param field Field name
     * @param direction sorting direction
     * @return next object in sorting chain. Add next sorting parameter (if any) to it
     */
    public Ordering Order(String field, Direction direction) {
        Ordering order = new Ordering(field, direction);
        this.child = order;
        return order;
    }

    /**
     * Get sort-by field name.
     * @return field name
     */
    public String getField() {
        return field;
    }

    /**
     * Get sorting direction
     * @return direction
     */
    public Direction getDirection() {
        return direction;
    }

    /**
     * Get next sorting object in chain.
     * @return next sorting object
     */
    public Ordering getChild() {
        return child;
    }

    /**
     * Create "Order by ..." implementation.
     * Use <code>fieldName</code> parameter to specify order-by field name <br />
     * Use <code>direction</code> parameter to specify order-by direction <br />
     * or <br />
     * Use <code>orderByDirectionParameterName</code> parameter to specify OrderBy.ORDER type method parameter name
     * to get order-by direction from.
     * @author Max Matveev
     *         Date: Dec 20, 2008
     *         Time: 4:59:47 PM
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Field {
        /** @return Order-by field name */
        String fieldName();
        /** @return Order direction */
        Direction direction() default Direction.ASC;
    }

    /**
     * Create "Order by ..." implementation.
     * Use on parameter to specify OrderBy.ORDER type method parameter
     * to get order-by direction from.
     * @author Max Matveev
     *         Date: Dec 20, 2008
     *         Time: 4:59:47 PM
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface Criteria {
    }
}
